package cn.tedu.submarine;

import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.Arrays;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;

/**
 * 窗口类
 * @author XingHaiYang
 * @date 2022/8/27 15:16
 */
public class World extends JPanel{
    public static final int WIDTH = 641;  //窗口的宽
    public static final int HEIGHT = 479; //窗口的高

    public static final int RUNNING = 0;   //运行状态
    public static final int PAUSE = 1;     //暂停状态
    public static final int GAME_OVER = 2; //游戏结束状态
    private int state = RUNNING; //当前状态(默认为运行状态)

    /**
     * 如下这一堆为窗口中所显示的对象,因为战舰只有一个，创建一个对象即可，
     * 潜艇、炸弹、水雷都不止一个，所以设计为数组结构
     */
    private Battleship ship = new Battleship(); //战舰
    private SeaObject[] submarines = {};        //潜艇(侦察潜艇、鱼雷潜艇、水雷潜艇)数组
    private Mine[] mines = {};                  //水雷数组
    private Bomb[] bombs = {};                  //深水炸弹数组

    /**
     * 重写JPanel类中的paint()方法
     * @param g 画笔
     */
    public void paint(Graphics g){
        Images.sea.paintIcon(null,g,0,0); //画海洋图
        ship.paintImage(g); //画战舰
        for(int i=0;i<submarines.length;i++){
            submarines[i].paintImage(g);// 画潜艇
        }
        for(int i=0;i<mines.length;i++){
            mines[i].paintImage(g);//画水雷
        }
        for(int i=0;i<bombs.length;i++){
            bombs[i].paintImage(g);//画炸弹
        }
        g.drawString("SCORE: "+score,200,50); //画分
        g.drawString("LIFE: "+ship.getLife(),400,50); //画命
        if(state==GAME_OVER){ //若当前状态为游戏结束状态
            Images.gameover.paintIcon(null,g,0,0); //画游戏结束图---不要求掌握
        }
    }

    /**
     * 生成潜艇(侦察潜艇、鱼雷潜艇、水雷潜艇)对象
     * @return 随机生成三种潜艇对象，因为返回的不止一种，所以用父类接收
     */
    private SeaObject nextSubmarine(){
        Random rand = new Random(); //随机数对象
        int type = rand.nextInt(20); //0到19之间
        if(type<10){ //0到9时，返回侦察潜艇
            return new ObserveSubmarine();
        }else if(type<15){ //10到14时，返回鱼雷潜艇
            return new TorpedoSubmarine();
        }else{ //15到19时，返回水雷潜艇
            return new MineSubmarine();
        }
    }

    private int subEnterIndex = 0; //潜艇入场计数
    /**
     * 潜艇(侦察潜艇、鱼雷潜艇、水雷潜艇)入场
     */
    private void submarineEnterAction(){ //每10毫秒走一次
        subEnterIndex++; //每10毫秒增1
        if(subEnterIndex%40==0){ //每400(40*10)毫秒走一次
            SeaObject obj = nextSubmarine(); //获取潜艇对象
            submarines = Arrays.copyOf(submarines,submarines.length+1); //扩容
            submarines[submarines.length-1] = obj; //将obj添加到submarines最后一个元素上
        }
    }

    private int mineEnterIndex = 0; //水雷入场计数
    /** 水雷入场 */
    private void mineEnterAction(){ //每10毫秒走一次
        mineEnterIndex++; //每10毫秒增1
        if(mineEnterIndex%100==0){ //每1000(100*10)毫秒走一次
            for(int i=0;i<submarines.length;i++){ //遍历所有潜艇
                if(submarines[i] instanceof MineSubmarine){ //若潜艇为水雷潜艇
                    MineSubmarine ms = (MineSubmarine)submarines[i]; //将潜艇强转为水雷潜艇
                    Mine obj = ms.shootMine(); //获取水雷对象
                    mines = Arrays.copyOf(mines,mines.length+1); //扩容
                    mines[mines.length-1] = obj; //将obj添加到mines最后一个元素上
                }
            }
        }
    }

    /** 海洋对象移动 */
    private void moveAction(){ //每10毫秒走一次
        for(int i=0;i<submarines.length;i++){ //遍历所有潜艇
            submarines[i].move(); //潜艇移动
        }
        for(int i=0;i<mines.length;i++){ //遍历所有水雷
            mines[i].move(); //水雷移动
        }
        for(int i=0;i<bombs.length;i++){ //遍历所有深水炸弹
            bombs[i].move(); //深水炸弹移动
        }
    }

    /** 删除越界的海洋对象----避免内存泄漏 */
    private void outOfBoundsAction(){ //每10毫秒走一次
        for(int i=0;i<submarines.length;i++){ //遍历所有潜艇
            if(submarines[i].isOutOfBounds() || submarines[i].isDead()){ //越界的
                submarines[i] = submarines[submarines.length-1]; //将越界潜艇替换为最后一个元素
                submarines = Arrays.copyOf(submarines,submarines.length-1); //缩容
            }
        }

        for(int i=0;i<mines.length;i++){ //遍历所有水雷
            if(mines[i].isOutOfBounds() || mines[i].isDead()){ //越界的，或者死了的
                mines[i] = mines[mines.length-1]; //将越界水雷替换为最后一个元素
                mines = Arrays.copyOf(mines,mines.length-1); //缩容
            }
        }

        for(int i=0;i<bombs.length;i++){ //遍历所有深水炸弹
            if(bombs[i].isOutOfBounds() || bombs[i].isDead()){ //越界的，或者死了的
                bombs[i] = bombs[bombs.length-1]; //将越界深水炸弹替换为最后一个元素
                bombs = Arrays.copyOf(bombs,bombs.length-1); //缩容
            }
        }
    }

    private int score = 0; //玩家得分
    /** 深水炸弹与潜艇的碰撞 */
    private void bombBangAction(){ //每10毫秒走一次
        for(int i=0;i<bombs.length;i++){ //遍历所有炸弹
            Bomb bomb = bombs[i]; //获取每个炸弹
            for(int j=0;j<submarines.length;j++){ //遍历所有潜艇
                SeaObject submarine = submarines[j]; //获取每个潜艇
                if(bomb.isLive() && submarine.isLive() && submarine.isHit(bomb)){ //若都活着并且还撞上了
                    submarine.goDead(); //潜艇去死
                    bomb.goDead(); //炸弹去死

                    if(submarine instanceof EnemyScore){ //若被撞对象为分
                        EnemyScore es = (EnemyScore)submarine; //将被撞对象强转为得分接口
                        score += es.getScore(); //玩家得分
                    }
                    if(submarine instanceof EnemyLife){ //若被撞对象为命
                        EnemyLife el = (EnemyLife)submarine; //将被撞对象强转为得命接口
                        int num = el.getLife(); //获取命数
                        ship.addLife(num); //战舰增命
                    }
                }
            }
        }
    }

    /** 水雷与战舰的碰撞 */
    private void mineBangAction(){ //每10毫秒走一次
        for(int i=0;i<mines.length;i++){ //遍历所有水雷
            Mine m = mines[i]; //获取每个水雷
            if(m.isLive() && ship.isLive() && ship.isHit(m)){ //若都活着并且还撞上了
                m.goDead(); //水雷去死
                ship.subtractLife(); //减命
            }
        }
    }

    /** 检测游戏结束 */
    private void checkGameOverAction(){ //每10毫秒走一次
        if(ship.getLife()<=0){ //若战舰的命数<=0，表示游戏结束了
            state = GAME_OVER; //将当前状态修改为GAME_OVER游戏结束状态
        }
    }

    /** 启动程序的执行 */
    private void action(){
        /** KeyAdapter为侦听器对象*/
        KeyAdapter k = new KeyAdapter() {
            /** 重写侦听器中的keyReleased()按键弹起事件 */
            public void keyReleased(KeyEvent e) { //当按键弹起时会自动触发
                if(state == RUNNING){ // 游戏运行状态下，监听的行为
                    if(e.getKeyCode() == KeyEvent.VK_SPACE){ //若按键是空格键
                        Bomb obj = ship.shootBomb(); //获取深水炸弹对象
                        bombs = Arrays.copyOf(bombs,bombs.length+1); //炸弹数组扩容
                        bombs[bombs.length-1] = obj; //将深水炸弹添加到bombs的最后一个元素上
                    }
                    if(e.getKeyCode() == KeyEvent.VK_LEFT){ //若按键是左键头
                        ship.moveLeft(); //战舰左移
                    }
                    if(e.getKeyCode() == KeyEvent.VK_RIGHT){ //若按键是右键头
                        ship.moveRight(); //战舰右移
                    }
                    if(e.getKeyCode() == KeyEvent.VK_P){ // 若按键为P键
                        if(state == RUNNING){ // 判断若是运行状态
                            state = PAUSE;// 改为暂停状态
                        }else{
                            state = RUNNING; // 反之，改为运行状态
                        }
                    }
                }
            }
        };
        this.addKeyListener(k); //调用监听器对象

        /** 定时器对象 */
        Timer timer = new Timer();
        int interval = 10; //定时间隔(以毫秒为单位)
        timer.schedule(new TimerTask() {
            public void run() { //定时干的事(每10毫秒自动执行)
                if(state == RUNNING){ // 游戏运行状态下，定时的行为
                    submarineEnterAction(); //潜艇(侦察潜艇、鱼雷潜艇、水雷潜艇)入场
                    mineEnterAction();      //水雷入场
                    moveAction();           //海洋对象移动
                    outOfBoundsAction(); // 对象越界删除
                    bombBangAction(); // 炸弹和潜艇相撞的方法
                    mineBangAction(); // 水雷和战舰相撞的方法
                    checkGameOverAction(); // 检测战舰的命数<=0，则游戏结束
                    repaint(); //重新调用paint()方法
                }
            }
        }, interval, interval);
    }

    /**
     * 程序的入口
     * @param args
     */
    public static void main(String[] args) {
        JFrame frame = new JFrame();
        World world = new World();
        world.setFocusable(true);
        frame.add(world);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(WIDTH+16, HEIGHT+39);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true); //自动调用paint()方法
        world.action();
    }

}
